package com.zmn.oms.third.yajule.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.zmn.common.utils.amount.AmountUtil;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.math.MoneyUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.manager.redis.RedisManager;
import com.zmn.oms.business.interfaces.messageV1.app.MessageSendAppService;
import com.zmn.oms.common.constant.MessageRuleIdConsts;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.constant.RedisKeyConsts;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.model.dto.order.proxy.PayOrderDTO;
import com.zmn.oms.model.entity.product.OrderProduct;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.product.OrderProductService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.third.yajule.YajuleConsts;
import com.zmn.oms.third.yajule.YajuleUtil;
import com.zmn.oms.third.yajule.dto.YajulePayRequestData;
import com.zmn.oms.third.yajule.dto.YajulePayResponseData;
import com.zmn.oms.third.yajule.dto.YajulePayResultData;
import com.zmn.oms.third.yajule.dto.YajuleRequest;
import com.zmn.oms.third.yajule.service.YajuleService;
import com.zmn.oms.zmn.business.interfaces.proxy.ProxyOrderBService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 雅居乐渠道对接接口
 *
 * @author xiewenbing
 * @date 2020/08/03
 */

@Service
@Slf4j
public class YajuleServiceImpl implements YajuleService {

    @Autowired
    private OrderWorkService orderWorkService;

    @Autowired
    private OrderDetailService orderDetailService;

    @Autowired
    private MessageSendAppService messageSendAppService;

    @Autowired
    private OrderProductService orderProductService;

    @Autowired
    private ProxyOrderBService proxyOrderBService;

    @Resource
    private RedisManager redisManager;

    /**
     * redis 缓存有效时间-10天
     */
    private final static int YAJULE_PAY_REDIS_TIMEOUT = 3600 * 24 * 10;
    /**
     * 判断是否为雅居乐平台渠道
     * @param channelId
     * @return
     */
    @Override
    public boolean determinYajuleChannel(Integer channelId) {
        return YajuleConsts.isYajuleChannel(channelId);
    }

    /**
     * 获取支付链接
     * @param orderId
     * @return
     */
    @Override
    public String getPayUrl(Long orderId) throws OmsBaseException {

        log.info("【{}】获取支付URL,订单id为:【{}】", YajuleConsts.CHANNEL_NAME,orderId);

        if (Objects.isNull(orderId)) {
            throw new OmsBaseException("错误的订单id");
        }

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, orderId);
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException("查找不到对应的订单");
        }

        if (!YajuleConsts.isYajuleChannel(orderWork.getChannelId())) {
            throw new OmsBaseException("非雅居乐平台的渠道");
        }

        List<OrderProduct> orderProductList = orderProductService.listOrderProductByOrderId(orderId);
        if (CollectionUtil.isNullOrEmpty(orderProductList)) {
            throw new OmsBaseException("订单没有选择产品");
        }

        // 读取 订单 支付次数的redis 缓存，未解决雅管家平台对于同一个订单不能多次发起支付请求而增加
        String redisKey = String.format(RedisKeyConsts.YAJULE_CHANNEL_PAY_KEY,orderId);
        Long payTimes = 0L;
        if (redisManager.exists(redisKey)) {
            payTimes = Long.valueOf(redisManager.get(redisKey));
        }

        payTimes ++;

        // 生成支付需要的业务数据
        YajulePayRequestData yajulePayRequestData = new YajulePayRequestData();
        yajulePayRequestData.setAppId(YajuleConsts.APP_ID);
        yajulePayRequestData.setOrderNo(String.format("%d_%04d",orderId,payTimes));
        yajulePayRequestData.setBeneficiaryUid(YajuleConsts.BENEFICIARY_UID);
        yajulePayRequestData.setOrderTotalMoney(orderWork.getMasterAmount().longValue());
        yajulePayRequestData.setOrderTotalPoint(0L);
        yajulePayRequestData.setSubject(orderProductList.get(0).getProductName());
        yajulePayRequestData.setBody(orderProductList.get(0).getProductName());
        yajulePayRequestData.setCallUrl(YajuleConsts.CALL_URL);
        yajulePayRequestData.setDisablePayWay("YADOU");
        yajulePayRequestData.setRandomCode(YajuleUtil.getRandomString(orderId));

        // 加密数据
        String payRequest = YajuleUtil.rsaEncrypt(JSON.toJSONString(yajulePayRequestData));
        if (StringUtil.isBlank(payRequest)) {
            throw new OmsBaseException("加密支付业务数据失败");
        }

        // 构造请求
        YajuleRequest yajuleRequest = new YajuleRequest();
        yajuleRequest.setVer(YajuleConsts.APP_VER);
        yajuleRequest.setAppId(YajuleConsts.APP_ID);
        yajuleRequest.setMethod(YajuleConsts.GET_PAY_URL_METHOD);
        yajuleRequest.setTimestamp(DateUtil.getNowTimestamp());
        yajuleRequest.setParams(String.format("{\"appId\":\"%s\",\"requestData\":\"%s\"}",YajuleConsts.APP_ID,payRequest));

        // 签名
        YajuleUtil.makeSign(yajuleRequest);

        // 保存发送记录
        redisManager.setex(redisKey,String.valueOf(payTimes),YAJULE_PAY_REDIS_TIMEOUT);

        // 发送请求
        log.info("【{}】发送获取支付URL请求,【{}】【{}】",YajuleConsts.CHANNEL_NAME,JSON.toJSONString(yajulePayRequestData),
                JSON.toJSONString(yajuleRequest));

        String responseContent = YajuleUtil.sendRequest(yajuleRequest);
        if (StringUtil.isBlank(responseContent)) {
            throw new OmsBaseException("发送请求失败，请重试");
        }

        log.info("【{}】获取支付URL应答,【{}】",YajuleConsts.CHANNEL_NAME,responseContent);
        YajulePayResponseData yajulePayResponseData = null;

        try {
            yajulePayResponseData = JSON.parseObject(responseContent,YajulePayResponseData.class);
        } catch (Exception e) {
            throw new OmsBaseException("获取的支付URL数据异常，请重试");
        }

        if (Objects.isNull(yajulePayResponseData) || StringUtil.isBlank(yajulePayResponseData.getPayQrCode())) {
            throw new OmsBaseException("获取的支付URL数据错误，请重试");
        }

        return yajulePayResponseData.getPayQrCode();
    }

    /**
     * 处理支付结果回调
     * @param resultData
     * @return 0，成功
     */
    @Override
    public int handlePayResultData(String resultData) throws OmsBaseException {

        if (StringUtil.isBlank(resultData)) {
            throw new OmsBaseException(1,"参数为空");
        }

        String payResultContent = YajuleUtil.rsaDecrypt(resultData);
        if (StringUtil.isBlank(payResultContent)){
            throw new OmsBaseException(2,"解密支付数据失败");
        }

        YajulePayResultData payResultData = JSON.parseObject(payResultContent,YajulePayResultData.class);
        if (Objects.isNull(payResultData)) {
            throw new OmsBaseException(3,"解析支付数据失败");
        }

        log.info("【{}】收到支付结果消息，支付流水号：【{}】，支付订单号：【{}】,订单金额：【{}】,支付状态：【{}】,支付方式：【{}】,支付时间：【{}】",
                YajuleConsts.CHANNEL_NAME,payResultData.getPayOrderNo(),payResultData.getOrderNo(),
                MoneyUtil.parseToYuan(payResultData.getOrderTotalMoney().intValue()),
                YajuleConsts.getPayStatus(payResultData.getPayStatus()),
                YajuleConsts.getPayWay(payResultData.getPayWay()),payResultData.getPayTimeStr());

        if (payResultData.getPayStatus() != YajuleConsts.PAY_RESULT_DONE) {
            throw new OmsBaseException(4,"支付状态不为支付完成");
        }

        String orderNo = payResultData.getOrderNo();
        Long orderId = Long.valueOf(orderNo.substring(0,orderNo.length()-5));
        if (NumberUtil.isNullOrZero(orderId)) {
            throw new OmsBaseException(5,"不正确的订单号");
        }

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, orderId);
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException(6,"查找不到对应的订单");
        }

        if (!YajuleConsts.isYajuleChannel(orderWork.getChannelId())) {
            throw new OmsBaseException(7,"订单渠道不为雅管家渠道");
        }

        if (orderWork.getMasterAmount() != payResultData.getOrderTotalMoney().intValue()) {
            throw new OmsBaseException(8,"支付总额与订单应收金额不一致");
        }
        
        // 修改订单的支付金额以及设置订单完成
        String logRemark = String.format("渠道支付金额:%.2f",payResultData.getOrderTotalMoney().doubleValue() / 100);
        PayOrderDTO payOrderDTO = new PayOrderDTO();
        payOrderDTO.setChannelId(orderWork.getChannelId());
        payOrderDTO.setOrderId(orderWork.getOrderId());
        payOrderDTO.setWorkId(orderWork.getWorkId());
        payOrderDTO.setPayTime(DateUtil.parse(payResultData.getPayTimeStr(),"yyyyMMddHHmmss"));

        payOrderDTO.setPayAmount(payResultData.getOrderTotalMoney().intValue());
        payOrderDTO.setOrderPayType(OrderConsts.API_ORDER_PAY_TYPE_CHANNEL_MASTER_AMOUNT);
        payOrderDTO.setOperatorLogRemark(logRemark);
        payOrderDTO.setOperatorRemark(logRemark);

        try {
            proxyOrderBService.payOrder(payOrderDTO);
        } catch (Exception e) {
            log.info("【{}】处理订单支付失败,【{}】【{}】",YajuleConsts.CHANNEL_NAME,e.getMessage(),payOrderDTO);
            throw new OmsBaseException(100,"处理订单支付失败");
        }

        this.pushPayMessage(payOrderDTO);

        // 删除对应的redis 缓存记录
        redisManager.del(String.format(RedisKeyConsts.YAJULE_CHANNEL_PAY_KEY,orderId));
        return YajuleConsts.CODE_SUCCESS;
    }

    /**
     * 向师傅APP端推送消息支付成功消息
     * @param payOrderDTO
     */
    private void pushPayMessage(PayOrderDTO payOrderDTO) {

        if (Objects.isNull(payOrderDTO)) {
            return;
        }

        // 支付成功消息push推送
        Map<String, Object> params = Maps.newHashMap();
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKey(payOrderDTO.getOrderId(), payOrderDTO.getWorkId());
        params.put("order_id", String.valueOf(dbOrderWork.getOrderId()));
        params.put("work_id", String.valueOf(dbOrderWork.getWorkId()));
        params.put("amount", String.valueOf(AmountUtil.fen2Yuan(payOrderDTO.getPayAmount()).doubleValue()));
        messageSendAppService.pushAppMessageInfo(MessageRuleIdConsts.PUSH_MSG_RULEID_ORDER_PAY,JSON.toJSONString(params),dbOrderWork);
    }

    public static void main(String[] args) {

        // 生成支付需要的业务数据
        YajulePayRequestData yajulePayRequestData = new YajulePayRequestData();
        yajulePayRequestData.setAppId(YajuleConsts.APP_ID);
        yajulePayRequestData.setOrderNo(String.valueOf(497342340055183375L));
        yajulePayRequestData.setBeneficiaryUid(YajuleConsts.BENEFICIARY_UID);
        yajulePayRequestData.setOrderTotalMoney(11000L);
        yajulePayRequestData.setOrderTotalPoint(0L);
        yajulePayRequestData.setSubject("油烟机清洗");
        yajulePayRequestData.setBody("油烟机清洗");
        yajulePayRequestData.setCallUrl(YajuleConsts.CALL_URL);
        yajulePayRequestData.setDisablePayWay("YADOU");
        yajulePayRequestData.setRandomCode(YajuleUtil.getRandomString(497342340055183360L));

        // 加密数据
        String payRequest = YajuleUtil.rsaEncrypt(JSON.toJSONString(yajulePayRequestData));
        if (StringUtil.isBlank(payRequest)) {
            System.out.println("加密支付业务数据失败");
            return;
        }

        // 构造请求
        YajuleRequest yajuleRequest = new YajuleRequest();
        yajuleRequest.setVer(YajuleConsts.APP_VER);
        yajuleRequest.setAppId(YajuleConsts.APP_ID);
        yajuleRequest.setMethod(YajuleConsts.GET_PAY_URL_METHOD);
        yajuleRequest.setTimestamp(DateUtil.getNowTimestamp());
        yajuleRequest.setParams(String.format("{\"appId\":\"%s\",\"requestData\":\"%s\"}",YajuleConsts.APP_ID,payRequest));

        // 签名
        YajuleUtil.makeSign(yajuleRequest);

        // 发送请求
        log.info("【{}】发送获取支付URL请求,【{}】【{}】",YajuleConsts.CHANNEL_NAME,JSON.toJSONString(yajulePayRequestData),
                JSON.toJSONString(yajuleRequest));

        String responseContent = YajuleUtil.sendRequest(yajuleRequest);
        if (StringUtil.isBlank(responseContent)) {
            System.out.println("发送请求失败，请重试");
            return;
        }

        log.info("【{}】获取支付URL应答,【{}】",YajuleConsts.CHANNEL_NAME,responseContent);
        YajulePayResponseData yajulePayResponseData = JSON.parseObject(responseContent,YajulePayResponseData.class);
        if (Objects.isNull(yajulePayResponseData) || StringUtil.isBlank(yajulePayResponseData.getPayQrCode())) {
            System.out.println("获取的支付URL数据错误，请重试");
            return;
        }

        System.out.println(yajulePayResponseData.getPayQrCode());
    }
}